package com.bage.finance.biz.service.impl;

import com.bage.common.exception.BizException;
import com.bage.common.service.TokenService;
import com.bage.finance.biz.config.ObjectConvertor;
import com.bage.finance.biz.domain.VoucherWordConfig;
import com.bage.finance.biz.dto.AdminDTO;
import com.bage.finance.biz.dto.form.CreateVoucherWordConfigForm;
import com.bage.finance.biz.dto.form.DelVoucherWordConfigForm;
import com.bage.finance.biz.dto.form.UpdateVoucherWordConfigDefaultFlagForm;
import com.bage.finance.biz.dto.form.UpdateVoucherWordConfigForm;
import com.bage.finance.biz.dto.vo.GetVoucherWordConfigVo;
import com.bage.finance.biz.dto.vo.ListVoucherWordConfigVo;
import com.bage.finance.biz.mapper.VoucherWordConfigMapper;
import com.bage.finance.biz.service.VoucherWordConfigService;
import com.bage.mybatis.help.MyBatisWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static com.bage.finance.biz.domain.VoucherWordConfigField.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class VoucherWordConfigServiceImpl implements VoucherWordConfigService {

    final TokenService<AdminDTO> tokenService;

    final VoucherWordConfigMapper voucherWordConfigMapper;

    final TransactionTemplate transactionTemplate;

    final ObjectConvertor objectConvertor;

    @Override
    public Boolean create(CreateVoucherWordConfigForm form) {
        // 查询凭证字信息
        VoucherWordConfig voucherWordConfig = getByVoucherWord(form.getVoucherWord());
        if (voucherWordConfig != null) {
            throw new BizException("凭证字已存在");
        }
        Boolean result = transactionTemplate.execute(transactionStatus -> {
            VoucherWordConfig insertVoucherWordConfig = objectConvertor.toVoucherWordConfig(form);
            insertVoucherWordConfig.initDefault();
            insertVoucherWordConfig.setMemberId(tokenService.getThreadLocalUserId());
            insertVoucherWordConfig.setTenantId(tokenService.getThreadLocalTenantId());
            insertVoucherWordConfig.setDefaultFlag(false);
            return voucherWordConfigMapper.insert(insertVoucherWordConfig) > 0;
        });
        return result == null ? false: result;
    }

    @Override
    public List<ListVoucherWordConfigVo> list() {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.select(Id, VoucherWord, PrintTitle, DefaultFlag, UseCount)
                .whereBuilder()
                .andEq(setTenantId(tokenService.getThreadLocalTenantId()))
                .andEq(setDelFlag(false));
        List<VoucherWordConfig> voucherWordConfigs = voucherWordConfigMapper.list(wrapper);
        return objectConvertor.toListVoucherWordConfigVo(voucherWordConfigs);
    }

    @Override
    public GetVoucherWordConfigVo getById(Long id) {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.select(Id, VoucherWord, PrintTitle, DefaultFlag)
                .whereBuilder()
                .andEq(Id, id)
                .andEq(TenantId, tokenService.getThreadLocalTenantId())
                .andEq(DelFlag, false);
        VoucherWordConfig voucherWordConfig = voucherWordConfigMapper.get(wrapper);
        if (voucherWordConfig == null) {
            throw new BizException("凭证字不存在");
        }
        return objectConvertor.toGetVoucherWordConfigVo(voucherWordConfig);
    }

    @Override
    public Boolean update(UpdateVoucherWordConfigForm form) {
        VoucherWordConfig voucherWordConfig = getByVoucherWord(form.getVoucherWord());
        if (voucherWordConfig != null && !Objects.equals(form.getId(), voucherWordConfig.getId())) {
            throw new BizException("凭证字已存在");
        }
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.update(VoucherWord, form.getVoucherWord())
                .update(PrintTitle, form.getPrintTitle())
                .update(UpdateMemberId, tokenService.getThreadLocalUserId())
                .update(UpdateTime, new Date())
                .whereBuilder()
                .andEq(Id, form.getId())
                .andEq(TenantId, tokenService.getThreadLocalTenantId());
        if (voucherWordConfigMapper.updateField(wrapper) == 0) {
            throw new BizException("修改失败");
        }
        return true;
    }

    @Override
    public Boolean updateDefaultFlag(UpdateVoucherWordConfigDefaultFlagForm form) {
        transactionTemplate.execute(transactionStatus -> {
            // 清空默认凭证,系统一定要保留一个默认凭证
            if (!clearDefault(form.getId())) {
                throw new BizException("修改默认凭证失败");
            }
            MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
            wrapper.update(DefaultFlag, true)
                    .update(UpdateMemberId, tokenService.getThreadLocalUserId())
                    .update(UpdateTime, new Date())
                    .whereBuilder()
                    .andEq(Id, form.getId())
                    .andEq(TenantId, tokenService.getThreadLocalTenantId())
                    .andEq(DefaultFlag, false)
                    .andEq(DelFlag, false);
            if (voucherWordConfigMapper.updateField(wrapper) == 0) {
                throw new BizException("修改失败");
            }
            return true;
        });
        return true;
    }

    @Override
    public Boolean del(DelVoucherWordConfigForm form) {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.updateConcat(setVoucherWord("_del_" + form.getId()))
                .update(DelFlag, true)
                .update(UpdateMemberId, tokenService.getThreadLocalUserId())
                .update(UpdateTime, new Date())
                .whereBuilder()
                .andEq(Id, form.getId())
                .andEq(setTenantId(tokenService.getThreadLocalTenantId()))
                .andEq(DelFlag, false)
                .andEq(DefaultFlag, false)
                .andEq(UseCount, 0);    // 未使用才能删除
        if (voucherWordConfigMapper.updateField(wrapper) == 0) {
            throw new BizException("删除失败");
        }
        return true;
    }

    @Override
    public boolean addUseCount(Long id, int count) {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.updateIncr(setUseCount(count))
                .whereBuilder()
                .andEq(Id, id);
        return voucherWordConfigMapper.updateField(wrapper) > 0;
    }

    @Override
    public boolean deductUseCount(Long id, int count) {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.updateDecr(setUseCount(count));
        wrapper.whereBuilder()
                .andEq(setId(id))
                .andGT(setUseCount(count));
        return voucherWordConfigMapper.updateField(wrapper) > 0;
    }

    @Override
    public List<VoucherWordConfig> listByIds(Set<Long> ids) {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.select(Id, VoucherWord)
                .whereBuilder()
                .andIn(Id, ids)
                .andEq(DelFlag, false)
                .andEq(TenantId, tokenService.getThreadLocalTenantId());
        return voucherWordConfigMapper.list(wrapper);
    }

    @Override
    public VoucherWordConfig getVoucherWordConfig(Long id) {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.select(Id, VoucherWord, PrintTitle, DefaultFlag)
                .whereBuilder()
                .andEq(Id, id)
                .andEq(DelFlag, false);
        VoucherWordConfig voucherWordConfig = voucherWordConfigMapper.get(wrapper);
        if (voucherWordConfig == null) {
            throw new BizException("凭证字不存在");
        }
        return voucherWordConfig;
    }

    /**
     * 清空默认凭证字(保证唯一默认凭证字)
     * @return
     */
    private boolean clearDefault(long id) {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.update(DefaultFlag, false)
                .update(UpdateMemberId, tokenService.getThreadLocalUserId())
                .update(UpdateTime, new Date())
                .whereBuilder()
                .andEq(DefaultFlag, true)
                .andEq(TenantId, tokenService.getThreadLocalTenantId())
                .andNE(Id, id);
        return voucherWordConfigMapper.updateField(wrapper) > 0;
    }

    /**
     * 查询凭证字信息
     * @param voucherWord
     * @return
     */
    private VoucherWordConfig getByVoucherWord(String voucherWord) {
        MyBatisWrapper<VoucherWordConfig> wrapper = new MyBatisWrapper<>();
        wrapper.select(Id, VoucherWord, PrintTitle)
                .whereBuilder()
                .andEq(setVoucherWord(voucherWord))
                .andEq(setTenantId(tokenService.getThreadLocalUserId()))
                .andEq(setDelFlag(false));
        return voucherWordConfigMapper.get(wrapper);
    }
}
